package com.admin_system.config;

import com.admin_system.pojo.User;
import com.admin_system.service.UserService;
import com.admin_system.utils.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * Spring Security 安全配置类
 * 负责配置Web应用的安全性，包括身份验证、授权和安全过滤器链
 * 同时集成了JWT令牌认证机制，支持前后端分离架构
 */
@Configuration
@EnableWebSecurity  // 启用Spring Security的Web安全支持
@EnableGlobalMethodSecurity(prePostEnabled = true)  // 启用方法级别的安全注解，如@PreAuthorize
public class WebSecurityConfig {

    /** 日志记录器 */
    private static final Logger logger = LoggerFactory.getLogger(WebSecurityConfig.class);

    /** JWT请求过滤器，用于拦截请求并验证令牌 */
    @Autowired
    @Lazy  // 使用延迟注入，避免循环依赖
    private JwtRequestFilter jwtRequestFilter;

    /** 用户详情服务，用于从数据库加载用户信息 */
    @Autowired
    private UserDetailsService userDetailsService;
    
    /** 用户服务，提供用户管理和令牌验证功能 */
    @Autowired
    private UserService userService;
    
    /** JWT令牌工具，处理令牌的生成和解析 */
    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    /**
     * 配置全局身份验证管理器
     * 设置用户详情服务和密码编码器
     *
     * @param auth 身份验证管理器构建器
     * @throws Exception 如果配置过程中发生错误
     */
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        // 配置UserDetailsService和密码加密器
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    /**
     * 密码编码器Bean
     * 使用BCrypt强哈希算法对密码进行加密
     *
     * @return BCrypt密码编码器实例
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 身份验证管理器Bean
     * 用于处理身份验证请求
     *
     * @param authConfig 身份验证配置
     * @return 身份验证管理器实例
     * @throws Exception 如果创建过程中发生错误
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
        return authConfig.getAuthenticationManager();
    }
    
    /**
     * 登录成功处理器
     * 当用户成功登录后执行的逻辑：
     * 1. 使旧令牌失效
     * 2. 生成新JWT令牌
     * 3. 根据请求类型返回不同的响应（JSON或重定向）
     *
     * @return 登录成功处理器实例
     */
    @Bean
    public AuthenticationSuccessHandler authenticationSuccessHandler() {
        return (request, response, authentication) -> {
            String username = authentication.getName();
            logger.info("用户 {} 登录成功", username);
            
            // 获取用户信息
            User user = userService.findByUsername(username);
            if (user != null) {
                // 先使该用户的所有现有令牌失效（实现单点登录）
                userService.invalidateUserTokens(username);
                
                // 生成新的JWT令牌
                String token = userService.generateUserToken(user);
                
                // 检查是否为AJAX请求（前后端分离场景）
                if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) {
                    // 返回JSON响应，包含令牌和用户信息
                    Map<String, Object> jsonResponse = new HashMap<>();
                    jsonResponse.put("success", true);
                    jsonResponse.put("message", "登录成功");
                    jsonResponse.put("token", token);
                    jsonResponse.put("username", user.getUsername());
                    jsonResponse.put("fullName", user.getFullName() != null ? user.getFullName() : user.getUsername());
                    jsonResponse.put("role", user.getRole());
                    
                    response.setContentType("application/json;charset=UTF-8");
                    response.getWriter().write(new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(jsonResponse));
                } else {
                    // 对于传统表单提交，将令牌保存在会话中并重定向到主页
                    request.getSession().setAttribute("jwtToken", token);
                    request.getSession().setAttribute("userFullName", user.getFullName());
                    request.getSession().setAttribute("userRole", user.getRole());
                    response.sendRedirect("/index.html");
                }
            } else {
                logger.error("登录后无法获取用户信息: {}", username);
                response.sendRedirect("/login.html?error=unknown");
            }
        };
    }
    
    /**
     * 登录失败处理器
     * 当用户登录失败时执行的逻辑，根据请求类型返回不同的响应
     *
     * @return 登录失败处理器实例
     */
    @Bean
    public AuthenticationFailureHandler authenticationFailureHandler() {
        return (request, response, exception) -> {
            logger.warn("用户登录失败: {}", exception.getMessage());
            
            // 检查是否为AJAX请求（前后端分离场景）
            if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) {
                response.setContentType("application/json;charset=UTF-8");
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.getWriter().write("{\"success\":false,\"message\":\"账号或密码错误\"}");
            } else {
                // 传统表单提交，重定向到带错误参数的登录页
                response.sendRedirect("/login.html?error");
            }
        };
    }

    /**
     * 安全过滤器链配置
     * 定义应用的安全策略，包括：
     * - URL访问权限控制
     * - 登录/登出配置
     * - 异常处理
     * - 会话管理
     * - JWT过滤器集成
     *
     * @param http HttpSecurity配置对象
     * @return 配置好的SecurityFilterChain
     * @throws Exception 如果配置过程中发生错误
     */
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // 禁用CSRF（跨站请求伪造）保护，因为使用JWT令牌认证
        http.csrf().disable()
                // 禁用HTTP基本认证
                .httpBasic().disable()
                // 配置路径访问权限
                .authorizeRequests()
                    // 允许所有静态资源的访问
                    .antMatchers("/", "/*.html", "/js/**", "/css/**", "/img/**", "/favicon.ico","favicon.png", "/assets/**").permitAll()
                    // 允许登录、注册和公共API的访问
                    .antMatchers("/login", "/register").permitAll()
                    // 允许找回密码相关路径的访问
                    .antMatchers("/forgot-password.html", "/api/forgot-password/**").permitAll()
                    // 允许公开物料访问路径
                    .antMatchers("/api/materials/public/**").permitAll()
                    // 所有其他请求都需要认证
                    .anyRequest().authenticated()
                .and()
                // 配置表单登录
                .formLogin()
                    .loginPage("/login.html") // 自定义登录页面
                    .loginProcessingUrl("/login") // 登录处理端点
                    .successHandler(authenticationSuccessHandler()) // 登录成功处理
                    .failureHandler(authenticationFailureHandler()) // 登录失败处理
                    .permitAll() // 登录相关的URL允许所有人访问
                .and()
                // 配置登出
                .logout()
                    .logoutUrl("/logout") // 登出处理URL
                    .logoutSuccessUrl("/login.html") // 登出成功后重定向的URL
                    .permitAll() // 登出URL允许所有人访问
                .and()
                // 配置异常处理（未授权访问）
                .exceptionHandling()
                    .authenticationEntryPoint((request, response, authException) -> {
                        // 根据请求类型决定如何处理未授权访问
                        if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With")) || 
                            request.getHeader("Accept") != null && request.getHeader("Accept").contains("application/json") ||
                            request.getHeader("Content-Type") != null && request.getHeader("Content-Type").contains("application/json")) {
                            // API请求返回JSON格式的401错误
                            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                            response.setContentType("application/json;charset=UTF-8");
                            response.getWriter().write("{\"error\":\"unauthorized\",\"message\":\"请先登录\"}");
                        } else {
                            // 页面请求重定向到登录页
                            response.setStatus(HttpServletResponse.SC_FOUND); // 302重定向
                            response.sendRedirect("/login.html");
                        }
                    })
                .and()
                // 配置无状态会话管理（JWT认证不需要服务器端会话）
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        // 添加JWT过滤器到Spring Security过滤器链
        // 确保JWT过滤器在用户名密码认证过滤器之前执行
        http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
        
        return http.build();
    }
} 